package model

import (
	"encoding/json"
	"gorm.io/gorm/clause"
	"server/common"
	"server/pkg/app"
	"server/pkg/cron"
)

type Bpipe struct {
	ID   int    `gorm:"primaryKey;"`
	Name string `json:"name" gorm:"column:name;not null;type:varchar(16);unique"`
}

func (pipe *Bpipe) TableName() string {
	return "pipeline"
}

type BasePipe struct {
	Model
	Name     string          `json:"name" gorm:"column:name;not null;type:varchar(16);unique"`
	Status   string          `json:"status" gorm:"column:status;not null;type:varchar(16)"`
	Type     string          `json:"type" gorm:"column:type;not null;type:varchar(16)"`
	Param    json.RawMessage `gorm:"column:param;type:json"`
	GroupStr json.RawMessage `gorm:"column:taskgroups;type:json" json:"groups"`
	cron.Cron
}

type PipeTask struct {
	Name   string `json:"name"`
	Status bool   `json:"status"`
}

type Groups struct {
	Name   string     `json:"name"`
	RunWay string     `json:"runway"`
	Status bool       `json:"status"`
	Tasks  []PipeTask `json:"tasks"`
}

func (pipe *BasePipe) TableName() string {
	return "pipeline"
}

type PipeLine struct {
	BasePipe

	OwnerID int `json:"owner_id"`
	Owner   Owner

	ProjectID int `json:"project_id"`
	Project   Project

	Env json.RawMessage `gorm:"column:env;type:json" json:"env"`

	HisPipes []HisPipe
	Users    []Owner `gorm:"many2many:user_pipeline;ForeignKey:ID;References:ID"`
}

type PipeApi struct {
	PipeLine
	TaskGroups []Groups `json:"group"`
}

func (pipe *PipeLine) TableName() string {
	return "pipeline"
}

func (pipe *PipeLine) Create() error {
	pipe.Status = common.IDLE
	if err := common.DB.Omit("Env").Create(&pipe).Error; err != nil {
		return err
	}
	return nil
}

func (pipe *PipeLine) List(page *app.Page) ([]PipeLine, int64) {
	pipes := []PipeLine{}
	var count int64
	if err := common.DB.Preload(clause.Associations).Order("id desc").Limit(page.Size).Offset((page.Page - 1) * page.Size).Find(&pipes).Offset(-1).Limit(-1).Count(&count).Error; err != nil {
		return pipes, count
	}
	return pipes, count
}

func (pipe *PipeLine) Info() *PipeLine {
	if err := common.DB.Where("name = ?", pipe.Name).Preload(clause.Associations).Find(&pipe).Error; err != nil {
		return pipe
	}
	return pipe
}

func (pipe *BasePipe) InfoOmit() *BasePipe {
	if err := common.DB.Omit("HisPipes").Where("name = ?", pipe.Name).Preload(clause.Associations).Find(&pipe).Error; err != nil {
		return pipe
	}
	return pipe
}

func (pipe *PipeLine) Update() error {
	if err := common.DB.Omit("Env").Where("name = ?", pipe.Name).Updates(&pipe).Error; err != nil {
		return err
	}
	return nil
}

func (pipe *PipeLine) UpdateStaus() error {
	if err := common.DB.Model(BasePipe{}).Omit(clause.Associations).Where("name = ?", pipe.Name).Update("status", pipe.Status).Error; err != nil {
		return err
	}
	return nil
}

func (pipe *PipeLine) SwitchCron() error {
	if err := common.DB.Model(PipeLine{}).Where("name = ?", pipe.Name).Update("switch", pipe.Switch).Error; err != nil {
		return err
	}
	return nil
}

func (pipe *PipeLine) Delete() error {
	if err := common.DB.Where("name = ?", pipe.Name).Delete(&pipe).Error; err != nil {
		return err
	}
	return nil
}

func (pipe *PipeLine) Query(page *app.Page) ([]PipeLine, int64, error) {
	pipes := []PipeLine{}
	var count int64
	if err := common.DB.Order("starttime desc").Limit(page.Size).Offset((page.Page - 1) * page.Size).Find(&pipes).Offset(-1).Limit(-1).Count(&count).Error; err != nil {
		return pipes, count, err
	}
	return pipes, count, nil
}

func (pipe *PipeLine) SearchByName(page *app.Page, key string) ([]PipeLine, int64, error) {
	pipes := []PipeLine{}
	var count int64
	if err := common.DB.Where("name like ?", "%"+key+"%").Order("starttime desc").Limit(page.Size).Offset((page.Page - 1) * page.Size).Find(&pipes).Offset(-1).Limit(-1).Count(&count).Error; err != nil {
		return pipes, count, err
	}
	return pipes, count, nil
}

func (pipe *PipeLine) SwitchOper() error {
	if err := common.DB.Where("name = ?", pipe.Name).Update("switch", pipe.Switch).Error; err != nil {
		return err
	}
	return nil
}
